import os
import time
import hashlib
from datetime import datetime, timedelta

import requests
from git import Repo, GitCommandError
from loguru import logger
from model.gitee import GiteeManger

GITEE_OWNER = os.getenv("gitee_username")
GITEE_REPO = "adguard"
GITEE_TOKEN = os.getenv("gitee_personal_access_token")
RELEASE_VERSION = "1.0"


# 配置部分
URL_LIST = {
    "filter_1.txt": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt",
    "filter_2.txt": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_2.txt",
    "kill-baidu-ad.txt": "https://cdn.jsdelivr.net/gh/banbendalao/ADgk@master/kill-baidu-ad.txt",
    "filter_59.txt":"https://adguardteam.github.io/HostlistsRegistry/assets/filter_59.txt",
    "filter_30.txt":"https://adguardteam.github.io/HostlistsRegistry/assets/filter_30.txt",
    "filter_55.txt":"https://adguardteam.github.io/HostlistsRegistry/assets/filter_55.txt",
    "filter_12.txt":"https://adguardteam.github.io/HostlistsRegistry/assets/filter_12.txt",
    "filter_52.txt":"https://adguardteam.github.io/HostlistsRegistry/assets/filter_52.txt",
    "filter_56.txt":"https://adguardteam.github.io/HostlistsRegistry/assets/filter_56.txt",
    "helloGithub.txt":"https://raw.hellogithub.com/hosts",
    "BlueSkyXN.txt":"https://raw.githubusercontent.com/BlueSkyXN/AdGuardHomeRules/master/skyrules.txt",
}
LOCAL_DIR = os.path.join(os.getcwd(), "txt")
CHECK_INTERVAL = 60  # 检查间隔（秒）
GIT_REPO_PATH = os.getcwd()  # 当前目录为 Git 仓库根目录
GIT_COMMIT_MSG = "feat: auto update txt files"
GIT_REMOTE_NAME = "origin"
GIT_BRANCH_NAME = "master"

def read_txt_file(file_name):
    """
    读取文本文件的内容

    参数:
    file_name (str): 文件的名称，包括路径

    返回:
    str: 文件的内容，如果发生错误则返回None
    """
    try:
        # 打开文件，使用with语句确保文件在使用后正确关闭
        with open(file_name, 'r', encoding='utf-8') as f:
            # 读取文件的全部内容
            content = f.read()
            # 返回文件内容
            return content
    except FileNotFoundError:
        # 如果文件不存在，打印错误信息并返回None
        print(f"[错误] 文件 {file_name} 不存在")
        return None
    except Exception as e:
        # 如果遇到其他异常，打印错误信息并返回None
        print(f"[错误] 读取文件 {file_name} 失败: {e}")
        return None


# 整合所有文本内容到一个文件
def integrate_text_files(output_file):
    """
    将多个文本文件内容整合到一个文件中。

    参数:
    output_file (str): 整合后的文本文件路径。

    返回:
    无
    """
    logger.info("[整合] 正在整合文本文件")
    input_files = os.listdir(LOCAL_DIR)
    try:
        with open(output_file, 'w+', encoding='utf-8') as f:
            for file in input_files:
                file = os.path.join(LOCAL_DIR, file)
                logger.debug(f"[读取] 正在读取文件 {file}")
                read_ = read_txt_file(file)
                if read_:
                    f.write(read_)
                else:
                    logger.warning(f"[读取] 文件 {file} 异常")
            f.close()
    except Exception as e:
        print(f"[错误] 写入文件 {output_file} 失败: {e}")
        return
    logger.info("[整合] 整合完成")
def ensure_local_dir():
    """
    确保本地目录存在。

    如果本地目录不存在，則创建它。这样做的目的是为了确保程序在进行文件操作时，
    目录存在，以避免文件写入时因目录不存在而导致的错误。
    """
    if not os.path.exists(LOCAL_DIR):
        os.makedirs(LOCAL_DIR)


def get_file_hash(content):
    """
    计算给定内容的MD5哈希值。

    该函数接受一个字符串内容作为输入，将其编码为UTF-8格式的字节串，
    然后使用MD5算法生成哈希值，并以十六进制字符串的形式返回。

    参数:
    content (str): 需要计算哈希值的字符串内容。

    返回:
    str: 内容的MD5哈希值，以十六进制字符串表示。
    """
    return hashlib.md5(content.encode('utf-8')).hexdigest()


def download_file(url):
    """
    通过指定的URL下载文件。

    此函数尝试通过HTTP GET请求从给定的URL下载内容。它使用了requests库来发起网络请求，
    并设置了10秒的请求超时时间。如果请求成功，它会返回响应的文本内容；
    如果请求失败，它会捕获异常并打印错误信息。

    参数:
    url (str): 需要下载文件的URL地址。

    返回:
    str: 如果下载成功，返回下载的文件内容；如果下载失败，返回None。
    """
    try:
        # 发起GET请求，同时设置超时时间为10秒
        response = requests.get(url, timeout=10)
        # 检查响应状态码，如果不是200，则抛出异常
        response.raise_for_status()
        # 返回响应的文本内容
        return response.text
    except Exception as e:
        # 打印下载失败的错误信息
        print(f"[错误] 下载失败 {url}: {e}")
        # 下载失败时返回None
        return None


def save_file(filename, content):
    """
    将给定的内容保存到指定的文件中。

    参数:
    filename (str): 要保存的文件的名称。
    content (str): 要写入文件的内容。

    返回:
    无
    """
    # 通过文件名和本地目录生成完整路径
    path = os.path.join(LOCAL_DIR, filename)

    # 打开文件，模式为写入，使用utf-8编码
    with open(path, 'w', encoding='utf-8') as f:
        # 将内容写入文件
        f.write(content)

    # 打印信息，表明文件已成功更新
    print(f"[保存] 已更新文件: {filename}")


def git_commit_and_push(updated_files):
    """
    将更新的文件提交到Git仓库并推送到远程仓库。

    参数:
    updated_files (list): 包含所有更新的文件路径的列表。

    返回:
    无
    """
    # 初始化Git仓库
    repo = Repo(GIT_REPO_PATH)

    # 检查仓库是否有未提交的更改或未跟踪的文件
    if repo.is_dirty(untracked_files=True):
        # 打印添加文件到暂存区的信息
        print("[Git] 添加文件到暂存区")
        # 将更新的文件添加到暂存区
        repo.index.add(updated_files)

        try:
            # 打印提交更改的信息
            print("[Git] 提交更改")
            # 提交更改到仓库
            repo.index.commit(GIT_COMMIT_MSG)

            # 打印推送到远程仓库的信息
            print("[Git] 推送到远程仓库")
            # 获取远程仓库对象
            origin = repo.remote(name=GIT_REMOTE_NAME)
            # 推送更改到远程仓库
            origin.push(refspec=f"{GIT_BRANCH_NAME}:{GIT_BRANCH_NAME}")
            # 打印成功提交并推送的信息
            print("✅ 成功提交并推送到 Git 远程仓库")
        except GitCommandError as e:
            # 打印提交或推送失败的错误信息
            print(f"[Git 错误] 提交或推送失败: {e}")
    else:
        # 打印没有需要提交的更改的信息
        print("[Git] 没有需要提交的更改")


def check_and_update():
    """
    检查并更新文件。

    本函数遍历URL_LIST中的文件URL，下载文件内容并与本地文件进行比较。
    如果本地文件不存在或内容有变化，则更新本地文件。
    如果有文件被更新，则进行git提交和推送。
    """
    # 初始化更新文件列表
    updated_files = []

    # 遍历URL_LIST中的文件URL
    for filename, url in URL_LIST.items():
        # 下载远程文件内容
        remote_content = download_file(url)
        # 如果远程内容为空，则跳过当前文件
        if not remote_content:
            continue

        # 构造本地文件路径
        local_path = os.path.join(LOCAL_DIR, filename)
        # 如果本地文件存在
        if os.path.exists(local_path):
            # 读取本地文件内容
            with open(local_path, 'r', encoding='utf-8') as f:
                local_content = f.read()
            # 如果本地文件内容与远程文件内容哈希值相同，说明文件没有更新
            if get_file_hash(local_content) == get_file_hash(remote_content):
                print(f"[无变化] {filename} 没有更新")
                continue

        # 如果文件有更新，打印更新信息并保存远程文件内容到本地
        print(f"[更新] 发现新版本: {filename}")
        save_file(filename, remote_content)
        # 将更新的文件路径添加到更新文件列表中
        updated_files.append(os.path.join(LOCAL_DIR, filename))

    # 如果有文件被更新，则进行git提交和推送
    if updated_files:
        # 开始合并
        ad = os.path.abspath("ad.txt")

        integrate_text_files(ad)
        git_commit_and_push(updated_files)

        gitee = GiteeManger(owner=GITEE_OWNER, repo=GITEE_REPO, token=GITEE_TOKEN)
        res = gitee.get_release_list()
        if res:
            gitee.delete_release(res[0]['id'])
        gitee.create_release()
        res = gitee.get_release_list()
        gitee.upload_file(ad, res[0]['id'])


if __name__ == "__main__":
    """
    程序入口点。
    首先确保本地目录存在，然后进入主循环，定期检查并更新内容。
    """
    ensure_local_dir()  # 确保程序所需的本地目录存在
    while True:
        check_and_update()  # 执行检查和更新操作
        logger.info(f"[检查] 下一次检查时间: {datetime.now() + timedelta(seconds=CHECK_INTERVAL)}", )
        time.sleep(CHECK_INTERVAL)  # 暂停一段时间，等待下一次检查

